﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Utilities
{
    [DesignTimeVisible(false)]
    [ToolboxItem(false)]
    public abstract class BaseMenuItem : Component, IDisposable
    {
        [Category("常用"), TypeConverter(typeof(StringConverter)), Description("与对象关联的用户自定义数据")]
        public object Tag { get; set; }
        internal Rectangle Bounds { get; set; }
        internal bool Selected;
        [Browsable(false)]
        [DefaultValue("")]
        [Category("常用"), Description("名称")]
        public string Name { get; set; }

        /// <summary>
        /// 所属Item集合
        /// </summary>
        internal MenuItemCollection OwnerItems
        {
            get;
            set;
        }

        /// <summary>
        /// 所属菜单
        /// </summary> 
        [Browsable(false)]
        public ContextMenuStrip MenuStrip
        {
            get
            {
                if (OwnerItems == null) return null;
                return OwnerItems.MenuStrip;
            }
        }

        /// <summary>
        /// 绘制菜单项
        /// </summary>
        internal abstract void Draw(Graphics g, ContextMenuStrip menu, ref TextItem dropItem);

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        public new virtual void Dispose()
        {
            Dispose(true);
        }

        public BaseMenuItem Clone()
        {
            return (BaseMenuItem)this.MemberwiseClone();
        }
    }

    [ToolboxItem(false)]
    public class TextItem : BaseMenuItem
    {
        [Category("常用"), Description("显示文本")]
        public string Text { get; set; }
        [Category("常用"), Description("图标")]
        public Image Image { get; set; }
        [Category("常用"), Description("快捷键文本")]
        public string QuickKey { get; set; }
        [Category("常用"), Description("可用状态"), DefaultValue(true)]
        public bool Enabled { get; set; }
        [Category("常用"), Description("勾选状态"), DefaultValue(false)]
        public bool Checked
        {
            get { return check; }
            set
            {
                check = value;
                if (MenuStrip != null)
                    MenuStrip.OnCheckChanged(this);
            }
        }
        [Category("常用"), Description("子菜单集合"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public MenuItemCollection Items
        {
            get;
            private set;
        }

        public event Action<TextItem> Click;

        private bool check;

        public TextItem()
        {
            Items = new MenuItemCollection(this);
            Enabled = true;
        }

        public TextItem(string name)
            : this()
        {
            Name = Text = name;
        }

        public void OnClick()
        {
            if (Click != null)
            {
                Click(this);
            }
        }

        internal override void Draw(Graphics g, ContextMenuStrip menu, ref TextItem dropItem)
        {
            int middleY = Bounds.Y + OwnerItems.ItemHeight / 2;
            //鼠标经过效果
            if (Selected && Enabled)
            {
                using (SolidBrush iBrush = new SolidBrush(menu.HoverColor))
                    g.FillRectangle(iBrush, Bounds);
            }
            //勾选效果
            if (Checked)
            {
                using (Pen iPen = new Pen(menu.MarkColor, 2))
                {
                    g.SmoothingMode = SmoothingMode.AntiAlias;
                    g.DrawLines(iPen, new Point[] { new Point(Bounds.X + 9, middleY - 1), new Point(Bounds.X + 13, middleY + 3), new Point(Bounds.X + 20, middleY - 4) });
                    g.SmoothingMode = SmoothingMode.Default;
                }
            }
            //图标
            else if (Image != null)
            {
                Image image = Enabled ? Image : DrawHelper.GetGrayImage(Image);
                Rectangle rect = new Rectangle(Bounds.X + (menu.ImageWidth - menu.ImageSize.Width) / 2, Bounds.Y + (OwnerItems.ItemHeight - menu.ImageSize.Height) / 2, menu.ImageSize.Width, menu.ImageSize.Height);
                g.DrawImage(image, rect, new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
            }
            //文本和快捷键文本
            using (SolidBrush iBrush = new SolidBrush(Enabled ? menu.ForeColor : menu.DisableColor))
            {
                Rectangle rect = new Rectangle(Bounds.X + menu.ImageWidth, Bounds.Y, OwnerItems.TextWidth, OwnerItems.ItemHeight);
                g.DrawString(Text, menu.Font, iBrush, rect, menu.Format);
                rect = new Rectangle(Bounds.X + menu.ImageWidth + OwnerItems.TextWidth, Bounds.Y, OwnerItems.QuickKeyWidth, OwnerItems.ItemHeight);
                g.DrawString(QuickKey, menu.Font, iBrush, rect, menu.Format);
            }
            //含子菜单的小三角以及子菜单
            if (Enabled && Items.Count > 0)
            {
                using (SolidBrush brush = new SolidBrush(Selected ? menu.ArrowHoverColor : menu.ArrowColor))
                    g.FillPolygon(brush, new Point[] { new Point(Bounds.X + OwnerItems.ItemWidth - 12, middleY - 4), new Point(Bounds.X + OwnerItems.ItemWidth - 12, middleY + 4), new Point(Bounds.X + OwnerItems.ItemWidth - 8, middleY) });
                if (Selected)
                {
                    dropItem = this;
                }
            }
        }

        protected override void Dispose(bool disposing)
        {
            Items.Clear();
            base.Dispose(disposing);
        }

    }

    /// <summary>
    /// 分割线
    /// </summary>
    [ToolboxItem(false)]
    public class SplitItem : BaseMenuItem
    {
        internal override void Draw(Graphics g, ContextMenuStrip menu, ref TextItem dropItem)
        {
            //using (Pen pen = new Pen(menu.BoderColor))
            //    g.DrawLine(pen, Bounds.X + 2, Bounds.Y + 1, Bounds.X + OwnerItems.ItemWidth - 2, Bounds.Y + 1);
            Rectangle rect = new Rectangle(Bounds.X + 2, Bounds.Y + 1, OwnerItems.ItemWidth - 4, 1);
            using (LinearGradientBrush brush = new LinearGradientBrush(rect, Color.Transparent, menu.BoderColor, LinearGradientMode.Horizontal))
            {
                Color[] colors = new Color[] { Color.Transparent, menu.BoderColor, menu.BoderColor, Color.Transparent };
                ColorBlend blend = new ColorBlend();
                blend.Positions = new float[] { 0, 0.2f,0.8f, 1 };
                blend.Colors = colors;
                brush.InterpolationColors = blend;
                g.FillRectangle(brush, rect);
            }
        }
    }

    /// <summary>
    /// 菜单项集合
    /// </summary>
    [Editor(typeof(ItemCollectionEditor), typeof(UITypeEditor))]
    public class MenuItemCollection : CollectionBase
    {
        internal int ItemWidth { get { return MenuStrip.ImageWidth + TextWidth + QuickKeyWidth + ArrowWidth; } }
        /// <summary>
        /// 左上角位置
        /// </summary>
        internal Point StartPos;
        internal Rectangle Bounds { get; set; }
        /// <summary>
        /// 文本宽度
        /// </summary>
        internal int TextWidth;
        /// <summary>
        /// 多级菜单箭头宽度
        /// </summary>
        internal readonly int ArrowWidth = 10;
        /// <summary>
        /// 菜单项高度
        /// </summary>
        internal int ItemHeight;
        /// <summary>
        /// 快捷键宽度
        /// </summary>
        internal int QuickKeyWidth;
        internal BaseMenuItem Owner
        {
            get;
            private set;
        }

        private ContextMenuStrip menuStrip;
        internal ContextMenuStrip MenuStrip
        {
            get
            {
                if (menuStrip == null)
                {
                    return Owner.MenuStrip;
                }
                else
                {
                    return menuStrip;
                }
            }

            set
            {
                menuStrip = value;
            }
        }

        public MenuItemCollection(BaseMenuItem parentMenu)
        {
            Owner = parentMenu;
        }

        public BaseMenuItem this[int index]
        {
            get
            {
                if (index >= 0 && index < List.Count)
                    return ((BaseMenuItem)List[index]);
                return null;
            }
            set { List[index] = value; }
        }

        public TextItem this[string name]
        {
            get
            {
                foreach (BaseMenuItem item in this.List)
                {
                    if (item.Name == name) return (TextItem)item;
                }
                return null;
            }
        }

        public int Add(BaseMenuItem value)
        {
            return List.Add(value);
        }

        public int IndexOf(BaseMenuItem value)
        {
            return List.IndexOf(value);
        }

        public void Insert(int index, BaseMenuItem value)
        {
            List.Insert(index, value);
        }

        public void Remove(BaseMenuItem value)
        {
            List.Remove(value);
        }

        public bool Contains(BaseMenuItem value)
        {
            return (List.Contains(value));
        }

        public new void Clear()
        {
            for (int i = this.Count - 1; i > -1; i--)
            {
                this[i].Dispose();
            }
            this.List.Clear();
        }

        protected override void OnInsertComplete(int index, object value)
        {
            base.OnInsertComplete(index, value);
            ((BaseMenuItem)value).OwnerItems = this;
        }

        protected override void OnRemove(int index, object value)
        {
            base.OnRemove(index, value);
            BaseMenuItem menu = (BaseMenuItem)value;
            menu.OwnerItems = null;
            menu.Dispose();
        }

        protected override void OnValidate(Object value)
        {
            if (value.GetType().BaseType != typeof(BaseMenuItem))
                throw new ArgumentException("value must be of type BaseMenuItem.", "value");
        }
    }
}
